/*message flow
include all data structure about message flow
*/
#include "los_typedef.h"

#include "cJSON.h"
#include "node_type.h"
#include "ext_node_type.h"
#include "securec.h"
#include "app_common.h"

#ifndef MESSAGE_FLOW_H
#define MESSAGE_FLOW_H

#define NODE_ID_MAX_LEN                 64
#define NODE_NAME_MAX_LEN               64
#define NODE_TAB_ID_MAX_LEN             32
#define NODE_TYPE_MAX_LEN               64
#define NODE_WIRES_MAX_LIMIT            64    // the num of hole
#define NODE_OUTPUT_WIRES_LIMIT         16    // wires links to one hole

#define IO_ATTR_NAME_MAX_LEN            32
#define IO_ATTR_TYPE_MAX_LEN            16
#define IO_ATTR_DATA_TYPE_MAX_LEN       16
#define IO_ATTR_SENSOR_TYPE_MAX_LEN     16

#define IOPUT_NAME_MAX_LEN              32
#define IOPUT_TYPE_MAX_LEN              32

#define FLOW_NODE_LIMITS                128

#define REGISTER_BASE_NODE_LIMITS       128

#define REGISTER_EXT_NODE_LIMITS        32

#define NODE_IO_LIMITS                  64

//modify by qinjx 20210127
#define PROCESS_THREAD_LIMIT            12    // producer consumer limits

#define QUEUE_MSG_LIMIT                 300

#define CENGINE_LOG_BUF_SIZE            (256)

typedef struct node_io_attribute
{
    UINT16          usio_attr_signal;
    UINT16          usio_attr_rc_priority;
    char            acio_attr_name[IO_ATTR_NAME_MAX_LEN];
    char            acio_attr_type[IO_ATTR_TYPE_MAX_LEN];
    char            acio_attr_data_type[IO_ATTR_DATA_TYPE_MAX_LEN];
    char            acio_attr_sensor_type[IO_ATTR_SENSOR_TYPE_MAX_LEN];
} node_io_attribute_t;

typedef struct node_ioput
{
    double          usioput_default_value;
    double          usioput_units_value;
    BOOL            bdisplay_ba_value;
    char            acnode_ioput_name[IOPUT_NAME_MAX_LEN];
    char            acnode_ioput_type[IOPUT_TYPE_MAX_LEN];
} node_ioput_t;

typedef struct node_input_wires
{
    UINT8           uwire_index;
    double          usin_data;
} node_input_wires_t;

typedef struct node_output_wires
{
    UINT8           uwire_index;
    double          usout_data;
} node_output_wires_t;

typedef struct node_input
{
    node_input_wires_t *poutput_wires[NODE_WIRES_MAX_LIMIT];
    UINT16              ussize;
} node_input_t;

typedef struct node_output
{
    node_output_wires_t *poutput_wires[NODE_WIRES_MAX_LIMIT];
    UINT16              ussize;
} node_output_t;

typedef struct output_wires
{    
    char            *pcwires[NODE_OUTPUT_WIRES_LIMIT]; // every wires link to this hole    
    UINT8           ucwire_num; // mark the num of wires links to this hole
} output_wires_t;

typedef struct flow_node_base
{
    char            acnode_id[NODE_ID_MAX_LEN];
    char            acnode_name[NODE_NAME_MAX_LEN];
    char            acnode_tab_id[NODE_TAB_ID_MAX_LEN];
    char            acnode_type[NODE_TYPE_MAX_LEN];
    flow_base_node_type_t enode_type;
    UINT8           ucnode_input;
    UINT8           ucnode_output;

    double          usrepeat; // for constant trigger only
    char            actrigger_id[NODE_ID_MAX_LEN]; // for 3 const 
    BOOL            bactive_flag; // for hybrid function

    node_io_attribute_t node_io_attr_ins;
    node_ioput_t    *pinput_arr[NODE_IO_LIMITS];		//output node use
    node_ioput_t    *poutput_arr[NODE_IO_LIMITS];		//input node use

    output_wires_t  *poutput_wires[NODE_WIRES_MAX_LIMIT];

    int( *pfnode_func) (struct flow_node_base *, node_input_wires_t *, node_output_t *);
    int( *pfnode_parse) (struct flow_node_base *, cJSON *);
} flow_node_base_t;

typedef int(*pfnode_func_t) (flow_node_base_t *, node_input_wires_t *, node_output_t *);
typedef int(*pfnode_parse_t) (flow_node_base_t *, cJSON *);

// parse status callback 1:success 0:failed
typedef void(*pfcengine_parse_status_callback_t) (int); 

// for register base node func
typedef struct register_node_base
{
    char            acnode_type[NODE_TYPE_MAX_LEN];
    flow_base_node_type_t enode_type;
    pfnode_func_t   pfnode_func;
    pfnode_parse_t  pfnode_parse;
} register_node_base_t;

// for register ext node func
typedef struct register_node_ext
{
    char            acnode_type[NODE_TYPE_MAX_LEN];
    flow_ext_node_type_t enode_type;
    pfnode_func_t   pfnode_func;
    pfnode_parse_t  pfnode_parse;
} register_node_ext_t;

// msg
typedef struct message_wire
{
    char            acwire_id[NODE_ID_MAX_LEN];
    double          wire_data;
} message_wrie_t;

typedef struct flow_message
{
    message_wrie_t  msg_payload;
    flow_node_base_t *pmsg_node;
    struct flow_message *next_msg;
} flow_messge_t;

enum cengine_node_run
{
    NODE_RUN_FAILED = -1, 
    NODE_RUN_SUCCESS = 0, 
    NODE_RUN_WITHOUT_PASS_MSG = 1
};

enum cengine_run_status
{
    CENGINE_ERROR = -1, 
    CENGINE_OK = 0
};

enum cengine_parse_data_status
{
    CENGINE_PARSE_FAILED = 0, 
    CENGINE_PARSE_SUCCESS = 1
};

typedef enum 
{
    CENGINE_LOG_DEBUG = 0, 
    CENGINE_LOG_INFO, 
    CENGINE_LOG_WARNING, 
    CENGINE_LOG_ERR, 
    CENGINE_LOG_FATAL, 
    
    CENGINE_LOG_MAX
} cengine_log_e;

cengine_log_e cengine_get_log_level(void);

int cengine_printf(const char *format, ...);

const char *cengine_get_log_level_name(cengine_log_e log_level);

#define CENGINE_LOG(level, fmt, ...)                                                              \
        do                                                                                        \
        {                                                                                         \
            if ((level) >= cengine_get_log_level())                                               \
            {                                                                                     \
                (void)cengine_printf("[%s][%s:%d] " fmt "\r\n",                                   \
                    cengine_get_log_level_name((level)), __FUNCTION__, __LINE__, ##__VA_ARGS__);  \
            }                                                                                     \
        } while (0)


// public function
void cengine_set_log_level(cengine_log_e log_level);
void cengine_register_all_nodes();
void cengine_parse_metadata(char *js_str, int len);
void cengine_process_init();

void cengine_init_flow_all_nodes();
void cengine_free_last_flow_resource();
void cengine_register_parse_status_callback(pfcengine_parse_status_callback_t callback);


// register base node
void cengine_register_base_node(const char *node_type, flow_base_node_type_t base_node_type, pfnode_func_t pfnode_func, pfnode_parse_t pfnode_parse);

// register ext node
void cengine_register_ext_node(const char *node_type, flow_ext_node_type_t ext_node_type, pfnode_func_t pfnode_func, pfnode_parse_t pfnode_parse);

// callback for node func
void cengine_add_queue_callback(flow_node_base_t *node, node_output_t *output);

// for hybrid func
flow_node_base_t *cengine_find_flow_node_by_id(char *node_id);

#endif